package userserv

import (
	"codedef"
	"encoding/json"
	"event"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/http"
	"rhelper"
	"time"
)

func updateControllerRelayWithReply(cid string, msgBuf []byte) {
	type Status struct {
		Relay string `json:"relay"`
	}

	var status Status
	err := json.Unmarshal(msgBuf, &status)
	if err != nil {
		log.Println("updateControllerRelay failed, parser err: ", err)
		return
	}

	updateControllerRelay(cid, status.Relay)
}

func isUserDeviceExist(userId string, cid string) bool {
	rconn := rhelper.Pool().Get()
	defer rconn.Close()

	values, _ := redis.Strings(rconn.Do("HMGET", rhelper.UserHash+userId, "account", "controllers"))
	if values[0] == "" || values[1] == "" {
		log.Println("account, controllers", values[0], values[1])
		return false
	}

	account := values[0]
	controllerStr := values[1]

	if !rhelper.CommaStringContain(controllerStr, cid) {
		return false
	}

	controllerValues, _ := redis.Strings(rconn.Do("HMGET", rhelper.ControllerHash+cid, "account", "shareAccount"))
	if account == controllerValues[0] || rhelper.CommaStringContain(controllerValues[1], account) {
		return true
	}

	return false

}

func saveRelayEvent(cid string, msgBuf []byte, success bool) {
	type Msg struct {
		Uri    string `json:"uri"`
		Action string `json:"action"`
	}

	var msg Msg
	err := json.Unmarshal(msgBuf, &msg)
	if err != nil {
		log.Println("saveRelayEvent failed, parser err: ", err)
		return
	}

	if msg.Uri == "/relay" {
		if success {
			event.SaveRelayEvent(cid, msg.Action+" success", "app")
		} else {
			event.SaveRelayEvent(cid, msg.Action+" failed", "app")
		}
	}

}

func onDevRequest(w http.ResponseWriter, r *http.Request) {
	var uniqueId string
	uniqueId = r.Header.Get("uniqueId")

	log.Printf("onDevRequest, uniqueId:%s\n", uniqueId)

	if r.ContentLength < 1 {
		log.Println("onDevRequest failed, content length is zero")
		replyError(w, codedef.ERR_REQUEST_INVALID_PARAM)
		return
	}

	message := make([]byte, r.ContentLength)
	n, _ := r.Body.Read(message)
	if n != int(r.ContentLength) {
		log.Println("onDevRequest failed, can't read request body")
		replyError(w, codedef.ERR_REQUEST_INVALID_PARAM)
		return
	}

	type DevRequestHead struct {
		ControllerId string `json:"cid"`
	}

	devRequestHead := DevRequestHead{}
	err := json.Unmarshal(message, &devRequestHead)
	if err != nil {
		log.Println("onDevRequest failed, json decode failed:", err)
		replyError(w, codedef.ERR_DECODE)
		return
	}

	if devRequestHead.ControllerId == "" {
		log.Println("onDevRequest failed, controller id is empty")
		replyError(w, codedef.ERR_REQUEST_INVALID_PARAM)
		return
	}

	if !isUserDeviceExist(uniqueId, devRequestHead.ControllerId) {
		log.Println("onDevRequest failed, controller not exist", devRequestHead.ControllerId)
		replyError(w, codedef.ERR_CONTROLLER_NOT_EXIST)
		return
	}

	controller := getOnlineControllerById(devRequestHead.ControllerId)
	if controller == nil {
		log.Println("onDevRequest failed, no online controller for:", devRequestHead.ControllerId)
		replyError(w, codedef.ERR_CONTROLLER_OFFLINE)
		return
	}

	if controller.isBusy() {
		log.Println("onDevRequest failed, controller is busy:", devRequestHead.ControllerId)
		replyError(w, codedef.ERR_CONTROLLER_BUSY)
		return
	}

	wait := make(chan []byte, 1)
	controller.onUserRequestWait(message, wait)
	select {
	case reply := <-wait:
		buf, errCode := parserDevReply(reply)
		if errCode != 0 {
			replyError(w, codedef.ERR_OPRATION_FAILD)
			return
		}

		replyBuffer(w, buf)
		updateControllerRelayWithReply(controller.Id, buf)
		saveRelayEvent(controller.Id, message, true)
		break
	case <-time.After(time.Second * 15):
		controller.giveupWaitAndDiscard()
		replyError(w, codedef.ERR_CONTROLLER_NO_RESPONSE)
		saveRelayEvent(controller.Id, message, false)
		log.Println("user request device timeout")
		break
	}
}

func init() {
	myMux.muxHandlers.HandleFunc("/devRequest", onDevRequest)
}
